namespace ActiveRecord

import System
import System.Reflection
import System.Collections.Generic

///<summary>This class only exists to provide a generic method for getting custom attributes for a type</summary>
static class AttrList: 
   public static def GetAssociationAttributes of T (activeRecType as Type) as Dictionary [of string, T]:
      #debug "GetAssociationAttributes(${activeRecType})"
      alist = Dictionary [of string, T]()
      atts = activeRecType.GetCustomAttributes(typeof(T), true)
      for att as T in atts:
         #debug " working with ${att}"
         relnAtt = att as AssociationAttribute
         if not Utils.IsEmpty(relnAtt.Table):
            alist.Add(relnAtt.Table, att)
         elif not Utils.IsEmpty(relnAtt.ClassName):
            alist.Add(relnAtt.ClassName, att)

      return alist


class ActiveRecordAttributeSet:
   [Property(ActiveRecordAttribute)]
   _activeRecordAttribute as ActiveRecordAttribute
   [Property(BelongsToAttributes)]
   _belongsToAttributes = Dictionary [of string, BelongsToAttribute]()
   [Property(HasAndBelongsToManyAttributes)]
   _hasAndBelongsToManyAttributes = Dictionary [of string, HasAndBelongsToManyAttribute]()
   [Property(HasManyAttributes)]
   _hasManyAttributes = Dictionary [of string, HasManyAttribute]()
   [Property(HasOneAttributes)]
   _hasOneAttributes = Dictionary [of string, HasOneAttribute]()
   
   public def ToString() as string:
      return "activeRecordAttribute: ${_activeRecordAttribute}, belongsToAttributes: ${_belongsToAttributes.Count}, hasAndBelongsToManyAttributes: ${_hasAndBelongsToManyAttributes.Count}, hasManyAttributes: ${_hasManyAttributes.Count}, hasOneAttributes: ${_hasOneAttributes.Count}"
   


[AttributeUsage(AttributeTargets.Class, AllowMultiple:true)]
abstract class ABaseAssociationAttribute(System.Attribute):
   public AssociationType as AssociationType


[AttributeUsage(AttributeTargets.Class, AllowMultiple:true)]
class AssociationAttribute(ABaseAssociationAttribute):
   [Property(AssociationForeignKey)] 
   _associationForeignKey as string
   [Property(ClassName)] // FIXME: Add support
   _className as string
   [Property(Conditions)]  // FIXME: Add support
   _conditions as string
   [Property(CounterCache)]
   _counterCache as string
   [Property(DeleteSql)] // FIXME: Add support
   _deleteSql as string
   [Property(FinderSql)] // FIXME: Add support
   _finderSql as string
   [Property(ForeignKey)] 
   _foreignKey as string
   [Property(Lazy)]
   _lazy = true
   [Property(InsertSql)]  // FIXME: Add support
   _insertSql as string
   [Property(OrderBy)]  // FIXME: Add support
   _orderBy as string
   [Property(Select)]  // FIXME: Add support
   _select as string
   [Property(Table)]
   _table as string
   [Property(Through)]
   _through as string
   
   public override def ToString() as string:
      return "${self.GetType()} - className: ${_className}, foreignKey: ${_foreignKey}, lazy: ${_lazy}, orderBy: ${_orderBy}, table: ${_table}, conditions: ${_conditions}"

[AttributeUsage(AttributeTargets.Class, AllowMultiple:true)]
class ActiveRecordAttribute(System.Attribute):
   [Property(ActsAsTree)]
   _actsAsTree as bool
   [Property(AssociationInheritancePK)]
   _associationInheritancePK as string
   [Property(InheritanceColumn)]
   _inheritanceColumn as string
   [Property(InheritanceTable)]
   _inheritanceTable as string
   [Property(PrimaryKey)]
   _primaryKey as string
   [Property(TableName)]
   _tableName as string
   [Property(TreeForeignKey)]
   _treeFK as string
   [Property(TreeOrderBy)]
   _treeOrderBy as string
   [Property(CounterCacheColumn)]
   _counterCacheColumn as string
   
   public override def ToString() as string:
      return "ActiveRecordAttribute - primaryKey: ${_primaryKey}, tableName: ${_tableName}, inheritance: ${_inheritanceTable}/${_inheritanceColumn}"

# Option examples:
#   belongs_to :firm, :foreign_key => "client_of"
#   belongs_to :author, :class_name => "Person", :foreign_key => "author_id"
#   belongs_to :valid_coupon, :class_name => "Coupon", :foreign_key => "coupon_id", 
#              :conditions => 'discounts > #{payments_count}'
[AttributeUsage(AttributeTargets.Class, AllowMultiple:true)]
class BelongsToAttribute(AssociationAttribute):
   def constructor():
      AssociationType = AssociationType.BelongsTo

[AttributeUsage(AttributeTargets.Class, AllowMultiple:true)]
class HasOneAttribute(AssociationAttribute):
   def constructor():
      AssociationType = AssociationType.HasOne

[AttributeUsage(AttributeTargets.Class, AllowMultiple:true)]
class HasManyAttribute(AssociationAttribute):
   def constructor():
      AssociationType = AssociationType.HasMany

[AttributeUsage(AttributeTargets.Class, AllowMultiple:true)]
class HasAndBelongsToManyAttribute(AssociationAttribute):
   def constructor():
      AssociationType = AssociationType.HasAndBelongsToMany
